﻿using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace TK.Common.Json
{
    /// <summary>
    /// 日期序列化
    /// </summary>
    public class DateTimeConverter : JsonConverterFactory
    {
        readonly string _dateFormat;

        /// <summary>
        /// ctor
        /// </summary>
        public DateTimeConverter(string dateFormat = "yyyy-MM-dd HH:mm:ss.ffff")
        { 
            _dateFormat = string.IsNullOrWhiteSpace(dateFormat) ? "yyyy-MM-dd HH:mm:ss.ffff" : dateFormat;
        }

        /// <summary>
        /// CanConvert
        /// </summary>
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert == typeof(DateTimeOffset) || typeToConvert == typeof(DateTime)
                || typeToConvert == typeof(DateTimeOffset?) || typeToConvert == typeof(DateTime?);
        }

        /// <summary>
        /// CreateConverter
        /// </summary>
        public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
        {
            if (typeof(DateTimeOffset) == typeToConvert)
            {
                return new DTOConverter(_dateFormat);
            }
            else if (typeof(DateTime) == typeToConvert)
            {
                return new DTConverter(_dateFormat);
            }
            else if (typeof(DateTimeOffset?) == typeToConvert)
            {
                return new DTONullConverter(_dateFormat);
            }
            else
            {
                return new DTNullConverter(_dateFormat);
            }
        }

        #region converter

        /// <summary>
        /// DateTimeOffset序列化
        /// </summary>
        private class DTOConverter : JsonConverter<DateTimeOffset>
        {
            string _dateFormat;
            public DTOConverter (string dateFormat)
            {
                _dateFormat= dateFormat;
            }
            /// <inheritdoc />
            public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                return DateTimeOffset.Parse(reader.GetString());
            }

            /// <inheritdoc />
            public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
            {
                writer.WriteStringValue(value.ToString(_dateFormat));
            }
        }

        /// <summary>
        /// DateTime序列化
        /// </summary>
        private class DTConverter : JsonConverter<DateTime>
        {
            string _dateFormat;
            public DTConverter(string dateFormat)
            {
                _dateFormat = dateFormat;
            }

            /// <inheritdoc />
            public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                return DateTime.Parse(reader.GetString());
            }

            /// <inheritdoc />
            public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
            {
                writer.WriteStringValue(value.ToString(_dateFormat));
            }
        }

        /// <summary>
        /// DateTimeOffset?序列化
        /// </summary>
        private class DTONullConverter : JsonConverter<DateTimeOffset?>
        {
            string _dateFormat;
            public DTONullConverter(string dateFormat)
            {
                _dateFormat = dateFormat;
            }

            /// <inheritdoc />
            public override DateTimeOffset? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                if (reader.TokenType == JsonTokenType.Null)
                {
                    return null;
                }
                else if (reader.TokenType == JsonTokenType.String)
                {
                    return DateTimeOffset.Parse(reader.GetString());
                }

                throw new NotSupportedException();
            }

            /// <inheritdoc />
            public override void Write(Utf8JsonWriter writer, DateTimeOffset? value, JsonSerializerOptions options)
            {
                if (value == null)
                {
                    writer.WriteNullValue();
                }
                else
                {
                    writer.WriteStringValue(value.Value.ToString(_dateFormat));
                }
            }
        }

        /// <summary>
        /// DateTime序列化
        /// </summary>
        private class DTNullConverter : JsonConverter<DateTime?>
        {
            string _dateFormat;
            public DTNullConverter(string dateFormat)
            {
                _dateFormat = dateFormat;
            }

            /// <inheritdoc />
            public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                if (reader.TokenType == JsonTokenType.Null)
                {
                    return null;
                }
                else if (reader.TokenType == JsonTokenType.String)
                {
                    return DateTime.Parse(reader.GetString());
                }

                throw new NotSupportedException();
            }

            /// <inheritdoc />
            public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
            {
                if (value == null)
                {
                    writer.WriteNullValue();
                }
                else
                {
                    writer.WriteStringValue(value.Value.ToString(_dateFormat));
                }
            }
        }
        #endregion
    }
}